home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Heretic Source / P_USER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-13  |  20.6 KB  |  1,008 lines

  1.  
  2. // P_user.c
  3.  
  4. #include "DoomDef.h"
  5. #include "P_local.h"
  6. #include "soundst.h"
  7.  
  8. void P_PlayerNextArtifact(player_t *player);
  9.  
  10. // Macros
  11.  
  12. #define MAXBOB 0x100000 // 16 pixels of bob
  13.  
  14. // Data
  15.  
  16. boolean onground;
  17. int newtorch; // used in the torch flicker effect.
  18. int newtorchdelta;
  19.  
  20. boolean WeaponInShareware[] =
  21. {
  22.     true,           // Staff
  23.     true,           // Gold wand
  24.     true,           // Crossbow
  25.     true,           // Blaster
  26.     false,          // Skull rod
  27.     false,          // Phoenix rod
  28.     false,          // Mace
  29.     true,           // Gauntlets
  30.     true            // Beak
  31. };
  32.  
  33. /*
  34. ==================
  35. =
  36. = P_Thrust
  37. =
  38. = moves the given origin along a given angle
  39. =
  40. ==================
  41. */
  42.  
  43. void P_Thrust(player_t *player, angle_t angle, fixed_t move)
  44. {
  45.     angle >>= ANGLETOFINESHIFT;
  46.     if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
  47.     {
  48.         player->mo->momx += FixedMul(move, finecosine[angle]);
  49.         player->mo->momy += FixedMul(move, finesine[angle]);
  50.     }
  51.     else if(player->mo->subsector->sector->special == 15) // Friction_Low
  52.     {
  53.         player->mo->momx += FixedMul(move>>2, finecosine[angle]);
  54.         player->mo->momy += FixedMul(move>>2, finesine[angle]);
  55.     }
  56.     else
  57.     {
  58.         player->mo->momx += FixedMul(move, finecosine[angle]);
  59.         player->mo->momy += FixedMul(move, finesine[angle]);
  60.     }
  61. }
  62.  
  63.  
  64. /*
  65. ==================
  66. =
  67. = P_CalcHeight
  68. =
  69. =Calculate the walking / running height adjustment
  70. =
  71. ==================
  72. */
  73.  
  74. void P_CalcHeight (player_t *player)
  75. {
  76.     int             angle;
  77.     fixed_t bob;
  78.  
  79. //
  80. // regular movement bobbing (needs to be calculated for gun swing even
  81. // if not on ground)
  82. // OPTIMIZE: tablify angle
  83.  
  84.     player->bob = FixedMul (player->mo->momx, player->mo->momx)+
  85.     FixedMul (player->mo->momy,player->mo->momy);
  86.     player->bob >>= 2;
  87.     if (player->bob>MAXBOB)
  88.         player->bob = MAXBOB;
  89.     if(player->mo->flags2&MF2_FLY && !onground)
  90.     {
  91.         player->bob = FRACUNIT/2;
  92.     }
  93.  
  94.     if ((player->cheats & CF_NOMOMENTUM))
  95.     {
  96.         player->viewz = player->mo->z + VIEWHEIGHT;
  97.         if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
  98.             player->viewz = player->mo->ceilingz-4*FRACUNIT;
  99.         player->viewz = player->mo->z + player->viewheight;
  100.         return;
  101.     }
  102.  
  103.     angle = (FINEANGLES/20*leveltime)&FINEMASK;
  104.     bob = FixedMul ( player->bob/2, finesine[angle]);
  105.  
  106. //
  107. // move viewheight
  108. //
  109.     if (player->playerstate == PST_LIVE)
  110.     {
  111.         player->viewheight += player->deltaviewheight;
  112.         if (player->viewheight > VIEWHEIGHT)
  113.         {
  114.             player->viewheight = VIEWHEIGHT;
  115.             player->deltaviewheight = 0;
  116.         }
  117.         if (player->viewheight < VIEWHEIGHT/2)
  118.         {
  119.             player->viewheight = VIEWHEIGHT/2;
  120.             if (player->deltaviewheight <= 0)
  121.                 player->deltaviewheight = 1;
  122.         }
  123.  
  124.         if (player->deltaviewheight)
  125.         {
  126.             player->deltaviewheight += FRACUNIT/4;
  127.             if (!player->deltaviewheight)
  128.                 player->deltaviewheight = 1;
  129.         }
  130.     }
  131.  
  132.     if(player->chickenTics)
  133.     {
  134.         player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
  135.     }
  136.     else
  137.     {
  138.         player->viewz = player->mo->z+player->viewheight+bob;
  139.     }
  140.     if(player->mo->flags2&MF2_FEETARECLIPPED
  141.         && player->playerstate != PST_DEAD
  142.         && player->mo->z <= player->mo->floorz)
  143.     {
  144.         player->viewz -= FOOTCLIPSIZE;
  145.     }
  146.     if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
  147.     {
  148.         player->viewz = player->mo->ceilingz-4*FRACUNIT;
  149.     }
  150.     if(player->viewz < player->mo->floorz+4*FRACUNIT)
  151.     {
  152.         player->viewz = player->mo->floorz+4*FRACUNIT;
  153.     }
  154. }
  155.  
  156. /*
  157. =================
  158. =
  159. = P_MovePlayer
  160. =
  161. =================
  162. */
  163.  
  164. void P_MovePlayer(player_t *player)
  165. {
  166.     int look;
  167.     int fly;
  168.     ticcmd_t *cmd;
  169.  
  170.     cmd = &player->cmd;
  171.     player->mo->angle += (cmd->angleturn<<16);
  172.  
  173.     onground = (player->mo->z <= player->mo->floorz
  174.         || (player->mo->flags2&MF2_ONMOBJ));
  175.  
  176.     if(player->chickenTics)
  177.     { // Chicken speed
  178.         if(cmd->forwardmove && (onground||player->mo->flags2&MF2_FLY))
  179.             P_Thrust(player, player->mo->angle, cmd->forwardmove*2500);
  180.         if(cmd->sidemove && (onground||player->mo->flags2&MF2_FLY))
  181.             P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2500);
  182.     }
  183.     else
  184.     { // Normal speed
  185.         if(cmd->forwardmove && (onground||player->mo->flags2&MF2_FLY))
  186.             P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
  187.         if(cmd->sidemove && (onground||player->mo->flags2&MF2_FLY))
  188.             P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
  189.     }
  190.  
  191.     if(cmd->forwardmove || cmd->sidemove)
  192.     {
  193.         if(player->chickenTics)
  194.         {
  195.             if(player->mo->state == &states[S_CHICPLAY])
  196.             {
  197.                 P_SetMobjState(player->mo, S_CHICPLAY_RUN1);
  198.             }
  199.         }
  200.         else
  201.         {
  202.             if(player->mo->state == &states[S_PLAY])
  203.             {
  204.                 P_SetMobjState(player->mo, S_PLAY_RUN1);
  205.             }
  206.         }
  207.     }
  208.  
  209.     look = cmd->lookfly&15;
  210.     if(look > 7)
  211.     {
  212.         look -= 16;
  213.     }
  214.     if(look)
  215.     {
  216.         if(look == TOCENTER)
  217.         {
  218.             player->centering = true;
  219.         }
  220.         else
  221.         {
  222.             player->lookdir += 5*look;
  223.             if(player->lookdir > 90 || player->lookdir < -110)
  224.             {
  225.                 player->lookdir -= 5*look;
  226.             }
  227.         }
  228.     }
  229.     if(player->centering)
  230.     {
  231.         if(player->lookdir > 0)
  232.         {
  233.             player->lookdir -= 8;
  234.         }
  235.         else if(player->lookdir < 0)
  236.         {
  237.             player->lookdir += 8;
  238.         }
  239.         if(abs(player->lookdir) < 8)
  240.         {
  241.             player->lookdir = 0;
  242.             player->centering = false;
  243.         }
  244.     }
  245.     fly = cmd->lookfly>>4;
  246.     if(fly > 7)
  247.     {
  248.         fly -= 16;
  249.     }
  250.     if(fly && player->powers[pw_flight])
  251.     {
  252.         if(fly != TOCENTER)
  253.         {
  254.             player->flyheight = fly*2;
  255.             if(!(player->mo->flags2&MF2_FLY))
  256.             {
  257.                 player->mo->flags2 |= MF2_FLY;
  258.                 player->mo->flags |= MF_NOGRAVITY;
  259.             }
  260.         }
  261.         else
  262.         {
  263.             player->mo->flags2 &= ~MF2_FLY;
  264.             player->mo->flags &= ~MF_NOGRAVITY;
  265.         }
  266.     }
  267.     else if(fly > 0)
  268.     {
  269.         P_PlayerUseArtifact(player, arti_fly);
  270.     }
  271.     if(player->mo->flags2&MF2_FLY)
  272.     {
  273.         player->mo->momz = player->flyheight*FRACUNIT;
  274.         if(player->flyheight)
  275.         {
  276.             player->flyheight /= 2;
  277.         }
  278.     }
  279. }
  280.  
  281. /*
  282. =================
  283. =
  284. = P_DeathThink
  285. =
  286. =================
  287. */
  288.  
  289. #define         ANG5    (ANG90/18)
  290.  
  291. void P_DeathThink(player_t *player)
  292. {
  293.     angle_t angle, delta;
  294.     extern int inv_ptr;
  295.     extern int curpos;
  296.     int lookDelta;
  297.  
  298.     P_MovePsprites(player);
  299.  
  300.     onground = (player->mo->z <= player->mo->floorz);
  301.     if(player->mo->type == MT_BLOODYSKULL)
  302.     { // Flying bloody skull
  303.         player->viewheight = 6*FRACUNIT;
  304.         player->deltaviewheight = 0;
  305.         //player->damagecount = 20;
  306.         if(onground)
  307.         {
  308.             if(player->lookdir < 60)
  309.             {
  310.                 lookDelta = (60-player->lookdir)/8;
  311.                 if(lookDelta < 1 && (leveltime&1))
  312.                 {
  313.                     lookDelta = 1;
  314.                 }
  315.                 else if(lookDelta > 6)
  316.                 {
  317.                     lookDelta = 6;
  318.                 }
  319.                 player->lookdir += lookDelta;
  320.             }
  321.         }
  322.     }
  323.     else
  324.     { // Fall to ground
  325.         player->deltaviewheight = 0;
  326.         if(player->viewheight > 6*FRACUNIT)
  327.             player->viewheight -= FRACUNIT;
  328.         if(player->viewheight < 6*FRACUNIT)
  329.             player->viewheight = 6*FRACUNIT;
  330.         if(player->lookdir > 0)
  331.         {
  332.             player->lookdir -= 6;
  333.         }
  334.         else if(player->lookdir < 0)
  335.         {
  336.             player->lookdir += 6;
  337.         }
  338.         if(abs(player->lookdir) < 6)
  339.         {
  340.             player->lookdir = 0;
  341.         }
  342.     }
  343.     P_CalcHeight(player);
  344.  
  345.     if(player->attacker && player->attacker != player->mo)
  346.     {
  347.         angle = R_PointToAngle2(player->mo->x, player->mo->y,
  348.             player->attacker->x, player->attacker->y);
  349.         delta = angle-player->mo->angle;
  350.         if(delta < ANG5 || delta > (unsigned)-ANG5)
  351.         { // Looking at killer, so fade damage flash down
  352.             player->mo->angle = angle;
  353.             if(player->damagecount)
  354.             {
  355.                 player->damagecount--;
  356.             }
  357.         }
  358.         else if(delta < ANG180)
  359.             player->mo->angle += ANG5;
  360.         else
  361.             player->mo->angle -= ANG5;
  362.     }
  363.     else if(player->damagecount)
  364.     {
  365.         player->damagecount--;
  366.     }
  367.  
  368.     if(player->cmd.buttons&BT_USE)
  369.     {
  370.         if(player == &players[consoleplayer])
  371.         {
  372.             I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
  373.             inv_ptr = 0;
  374.             curpos = 0;
  375.             newtorch = 0;
  376.             newtorchdelta = 0;
  377.         }
  378.         player->playerstate = PST_REBORN;
  379.         // Let the mobj know the player has entered the reborn state.  Some
  380.         // mobjs need to know when it's ok to remove themselves.
  381.         player->mo->special2 = 666;
  382.     }
  383. }
  384.  
  385. //----------------------------------------------------------------------------
  386. //
  387. // PROC P_ChickenPlayerThink
  388. //
  389. //----------------------------------------------------------------------------
  390.  
  391. void P_ChickenPlayerThink(player_t *player)
  392. {
  393.     mobj_t *pmo;
  394.  
  395.     if(player->health > 0)
  396.     { // Handle beak movement
  397.         P_UpdateBeak(player, &player->psprites[ps_weapon]);
  398.     }
  399.     if(player->chickenTics&15)
  400.     {
  401.         return;
  402.     }
  403.     pmo = player->mo;
  404.     if(!(pmo->momx+pmo->momy) && P_Random() < 160)
  405.     { // Twitch view angle
  406.         pmo->angle += (P_Random()-P_Random())<<19;
  407.     }
  408.     if((pmo->z <= pmo->floorz) && (P_Random() < 32))
  409.     { // Jump and noise
  410.         pmo->momz += FRACUNIT;
  411.         P_SetMobjState(pmo, S_CHICPLAY_PAIN);
  412.         return;
  413.     }
  414.     if(P_Random() < 48)
  415.     { // Just noise
  416.         S_StartSound(pmo, sfx_chicact);
  417.     }
  418. }
  419.  
  420. //----------------------------------------------------------------------------
  421. //
  422. // FUNC P_GetPlayerNum
  423. //
  424. //----------------------------------------------------------------------------
  425.  
  426. int P_GetPlayerNum(player_t *player)
  427. {
  428.     int i;
  429.  
  430.     for(i = 0; i < MAXPLAYERS; i++)
  431.     {
  432.         if(player == &players[i])
  433.         {
  434.             return(i);
  435.         }
  436.     }
  437.     return(0);
  438. }
  439.  
  440. //----------------------------------------------------------------------------
  441. //
  442. // FUNC P_UndoPlayerChicken
  443. //
  444. //----------------------------------------------------------------------------
  445.  
  446. boolean P_UndoPlayerChicken(player_t *player)
  447. {
  448.     mobj_t *fog;
  449.     mobj_t *mo;
  450.     mobj_t *pmo;
  451.     fixed_t x;
  452.     fixed_t y;
  453.     fixed_t z;
  454.     angle_t angle;
  455.     int playerNum;
  456.     weapontype_t weapon;
  457.     int oldFlags;
  458.     int oldFlags2;
  459.  
  460.     pmo = player->mo;
  461.     x = pmo->x;
  462.     y = pmo->y;
  463.     z = pmo->z;
  464.     angle = pmo->angle;
  465.     weapon = pmo->special1;
  466.     oldFlags = pmo->flags;
  467.     oldFlags2 = pmo->flags2;
  468.     P_SetMobjState(pmo, S_FREETARGMOBJ);
  469.     mo = P_SpawnMobj(x, y, z, MT_PLAYER);
  470.     if(P_TestMobjLocation(mo) == false)
  471.     { // Didn't fit
  472.         P_RemoveMobj(mo);
  473.         mo = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
  474.         mo->angle = angle;
  475.         mo->health = player->health;
  476.         mo->special1 = weapon;
  477.         mo->player = player;
  478.         mo->flags = oldFlags;
  479.         mo->flags2 = oldFlags2;
  480.         player->mo = mo;
  481.         player->chickenTics = 2*35;
  482.         return(false);
  483.     }
  484.     playerNum = P_GetPlayerNum(player);
  485.     if(playerNum != 0)
  486.     { // Set color translation
  487.         mo->flags |= playerNum<<MF_TRANSSHIFT;
  488.     }
  489.     mo->angle = angle;
  490.     mo->player = player;
  491.     mo->reactiontime = 18;
  492.     if(oldFlags2&MF2_FLY)
  493.     {
  494.         mo->flags2 |= MF2_FLY;
  495.         mo->flags |= MF_NOGRAVITY;
  496.     }
  497.     player->chickenTics = 0;
  498.     player->powers[pw_weaponlevel2] = 0;
  499.     player->health = mo->health = MAXHEALTH;
  500.     player->mo = mo;
  501.     angle >>= ANGLETOFINESHIFT;
  502.     fog = P_SpawnMobj(x+20*finecosine[angle],
  503.         y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
  504.     S_StartSound(fog, sfx_telept);
  505.     P_PostChickenWeapon(player, weapon);
  506.     return(true);
  507. }
  508.  
  509. //----------------------------------------------------------------------------
  510. //
  511. // PROC P_PlayerThink
  512. //
  513. //----------------------------------------------------------------------------
  514.  
  515. void P_PlayerThink(player_t *player)
  516. {
  517.     ticcmd_t *cmd;
  518.     weapontype_t newweapon;
  519.  
  520.     extern boolean ultimatemsg;
  521.  
  522.     // No-clip cheat
  523.     if(player->cheats&CF_NOCLIP)
  524.     {
  525.         player->mo->flags |= MF_NOCLIP;
  526.     }
  527.     else
  528.     {
  529.         player->mo->flags &= ~MF_NOCLIP;
  530.     }
  531.     cmd = &player->cmd;
  532.     if(player->mo->flags&MF_JUSTATTACKED)
  533.     { // Gauntlets attack auto forward motion
  534.         cmd->angleturn = 0;
  535.         cmd->forwardmove = 0xc800/512;
  536.         cmd->sidemove = 0;
  537.         player->mo->flags &= ~MF_JUSTATTACKED;
  538.     }
  539. // messageTics is above the rest of the counters so that messages will
  540. //              go away, even in death.
  541.     player->messageTics--; // Can go negative
  542.     if(!player->messageTics)
  543.     { // Refresh the screen when a message goes away
  544.         ultimatemsg = false; // clear out any chat messages.
  545.         BorderTopRefresh = true;
  546.     }
  547.     if(player->playerstate == PST_DEAD)
  548.     {
  549.         P_DeathThink(player);
  550.         return;
  551.     }
  552.     if(player->chickenTics)
  553.     {
  554.         P_ChickenPlayerThink(player);
  555.     }
  556.     // Handle movement
  557.     if(player->mo->reactiontime)
  558.     { // Player is frozen
  559.         player->mo->reactiontime--;
  560.     }
  561.     else
  562.     {
  563.         P_MovePlayer(player);
  564.     }
  565.     P_CalcHeight(player);
  566.     if(player->mo->subsector->sector->special)
  567.     {
  568.         P_PlayerInSpecialSector(player);
  569.     }
  570.     if(cmd->arti)
  571.     { // Use an artifact
  572.         if(cmd->arti == 0xff)
  573.         {
  574.             P_PlayerNextArtifact(player);
  575.         }
  576.         else
  577.         {
  578.             P_PlayerUseArtifact(player, cmd->arti);
  579.         }
  580.     }
  581.     // Check for weapon change
  582.     if(cmd->buttons&BT_SPECIAL)
  583.     { // A special event has no other buttons
  584.         cmd->buttons = 0;
  585.     }
  586.     if(cmd->buttons&BT_CHANGE)
  587.     {
  588.         // The actual changing of the weapon is done when the weapon
  589.         // psprite can do it (A_WeaponReady), so it doesn't happen in
  590.         // the middle of an attack.
  591.         newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
  592.         if(newweapon == wp_staff && player->weaponowned[wp_gauntlets]
  593.             && !(player->readyweapon == wp_gauntlets))
  594.         {
  595.             newweapon = wp_gauntlets;
  596.         }
  597.         if(player->weaponowned[newweapon]
  598.             && newweapon != player->readyweapon)
  599.         {
  600.             if(WeaponInShareware[newweapon] || !shareware)
  601.             {
  602.                 player->pendingweapon = newweapon;
  603.             }
  604.         }
  605.     }
  606.     // Check for use
  607.     if(cmd->buttons&BT_USE)
  608.     {
  609.         if(!player->usedown)
  610.         {
  611.             P_UseLines(player);
  612.             player->usedown = true;
  613.         }
  614.     }
  615.     else
  616.     {
  617.         player->usedown = false;
  618.     }
  619.     // Chicken counter
  620.     if(player->chickenTics)
  621.     {
  622.         if(player->chickenPeck)
  623.         { // Chicken attack counter
  624.             player->chickenPeck -= 3;
  625.         }
  626.         if(!--player->chickenTics)
  627.         { // Attempt to undo the chicken
  628.             P_UndoPlayerChicken(player);
  629.         }
  630.     }
  631.     // Cycle psprites
  632.     P_MovePsprites(player);
  633.     // Other Counters
  634.     if(player->powers[pw_invulnerability])
  635.     {
  636.         player->powers[pw_invulnerability]--;
  637.     }
  638.     if(player->powers[pw_invisibility])
  639.     {
  640.         if(!--player->powers[pw_invisibility])
  641.         {
  642.             player->mo->flags &= ~MF_SHADOW;
  643.         }
  644.     }
  645.     if(player->powers[pw_infrared])
  646.     {
  647.         player->powers[pw_infrared]--;
  648.     }
  649.     if(player->powers[pw_flight])
  650.     {
  651.         if(!--player->powers[pw_flight])
  652.         {
  653. #ifdef __WATCOMC__
  654.             if(player->mo->z != player->mo->floorz && !useexterndriver)
  655.             {
  656.                 player->centering = true;
  657.             }
  658. #else
  659.             if(player->mo->z != player->mo->floorz)
  660.             {
  661.                 player->centering = true;
  662.             }
  663. #endif
  664.  
  665.             player->mo->flags2 &= ~MF2_FLY;
  666.             player->mo->flags &= ~MF_NOGRAVITY;
  667.             BorderTopRefresh = true; //make sure the sprite's cleared out
  668.         }
  669.     }
  670.     if(player->powers[pw_weaponlevel2])
  671.     {
  672.         if(!--player->powers[pw_weaponlevel2])
  673.         {
  674.             if((player->readyweapon == wp_phoenixrod)
  675.                 && (player->psprites[ps_weapon].state
  676.                 != &states[S_PHOENIXREADY])
  677.                 && (player->psprites[ps_weapon].state
  678.                 != &states[S_PHOENIXUP]))
  679.             {
  680.                 P_SetPsprite(player, ps_weapon, S_PHOENIXREADY);
  681.                 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
  682.                 player->refire = 0;
  683.             }
  684.             else if((player->readyweapon == wp_gauntlets)
  685.                 || (player->readyweapon == wp_staff))
  686.             {
  687.                 player->pendingweapon = player->readyweapon;
  688.             }
  689.             BorderTopRefresh = true;
  690.         }
  691.     }
  692.     if(player->damagecount)
  693.     {
  694.         player->damagecount--;
  695.     }
  696.     if(player->bonuscount)
  697.     {
  698.         player->bonuscount--;
  699.     }
  700.     // Colormaps
  701.     if(player->powers[pw_invulnerability])
  702.     {
  703.         if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
  704.             || (player->powers[pw_invulnerability]&8))
  705.         {
  706.             player->fixedcolormap = INVERSECOLORMAP;
  707.         }
  708.         else
  709.         {
  710.             player->fixedcolormap = 0;
  711.         }
  712.     }
  713.     else if(player->powers[pw_infrared])
  714.     {
  715.         if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
  716.         {
  717.             if(player->powers[pw_infrared]&8)
  718.             {
  719.                 player->fixedcolormap = 0;
  720.             }
  721.             else
  722.             {
  723.                 player->fixedcolormap = 1;
  724.             }
  725.         }
  726.         else if(!(leveltime&16) && player == &players[consoleplayer])
  727.         {
  728.             if(newtorch)
  729.             {
  730.                 if(player->fixedcolormap+newtorchdelta > 7
  731.                     || player->fixedcolormap+newtorchdelta < 1
  732.                     || newtorch == player->fixedcolormap)
  733.                 {
  734.                     newtorch = 0;
  735.                 }
  736.                 else
  737.                 {
  738.                     player->fixedcolormap += newtorchdelta;
  739.                 }
  740.             }
  741.             else
  742.             {
  743.                 newtorch = (M_Random()&7)+1;
  744.                 newtorchdelta = (newtorch == player->fixedcolormap) ?
  745.                         0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
  746.             }
  747.         }
  748.     }
  749.     else
  750.     {
  751.         player->fixedcolormap = 0;
  752.     }
  753. }
  754.  
  755. //----------------------------------------------------------------------------
  756. //
  757. // PROC P_ArtiTele
  758. //
  759. //----------------------------------------------------------------------------
  760.  
  761. void P_ArtiTele(player_t *player)
  762. {
  763.     int i;
  764.     int selections;
  765.     fixed_t destX;
  766.     fixed_t destY;
  767.     angle_t destAngle;
  768.  
  769.     if(deathmatch)
  770.     {
  771.         selections = deathmatch_p-deathmatchstarts;
  772.         i = P_Random()%selections;
  773.         destX = deathmatchstarts[i].x<<FRACBITS;
  774.         destY = deathmatchstarts[i].y<<FRACBITS;
  775.         destAngle = ANG45*(deathmatchstarts[i].angle/45);
  776.     }
  777.     else
  778.     {
  779.         destX = playerstarts[0].x<<FRACBITS;
  780.         destY = playerstarts[0].y<<FRACBITS;
  781.         destAngle = ANG45*(playerstarts[0].angle/45);
  782.     }
  783.     P_Teleport(player->mo, destX, destY, destAngle);
  784.     S_StartSound(NULL, sfx_wpnup); // Full volume laugh
  785. }
  786.  
  787. //----------------------------------------------------------------------------
  788. //
  789. // PROC P_PlayerNextArtifact
  790. //
  791. //----------------------------------------------------------------------------
  792.  
  793. void P_PlayerNextArtifact(player_t *player)
  794. {
  795.     extern int inv_ptr;
  796.     extern int curpos;
  797.  
  798.     if(player == &players[consoleplayer])
  799.     {
  800.         inv_ptr--;
  801.         if(inv_ptr < 6)
  802.         {
  803.             curpos--;
  804.             if(curpos < 0)
  805.             {
  806.                 curpos = 0;
  807.             }
  808.         }
  809.         if(inv_ptr < 0)
  810.         {
  811.             inv_ptr = player->inventorySlotNum-1;
  812.             if(inv_ptr < 6)
  813.             {
  814.                 curpos = inv_ptr;
  815.             }
  816.             else
  817.             {
  818.                 curpos = 6;
  819.             }
  820.         }
  821.         player->readyArtifact =
  822.             player->inventory[inv_ptr].type;
  823.     }
  824. }
  825.  
  826. //----------------------------------------------------------------------------
  827. //
  828. // PROC P_PlayerRemoveArtifact
  829. //
  830. //----------------------------------------------------------------------------
  831.  
  832. void P_PlayerRemoveArtifact(player_t *player, int slot)
  833. {
  834.     int i;
  835.     extern int inv_ptr;
  836.     extern int curpos;
  837.  
  838.     player->artifactCount--;
  839.     if(!(--player->inventory[slot].count))
  840.     { // Used last of a type - compact the artifact list
  841.         player->readyArtifact = arti_none;
  842.         player->inventory[slot].type = arti_none;
  843.         for(i = slot+1; i < player->inventorySlotNum; i++)
  844.         {
  845.             player->inventory[i-1] = player->inventory[i];
  846.         }
  847.         player->inventorySlotNum--;
  848.         if(player == &players[consoleplayer])
  849.         { // Set position markers and get next readyArtifact
  850.             inv_ptr--;
  851.             if(inv_ptr < 6)
  852.             {
  853.                 curpos--;
  854.                 if(curpos < 0)
  855.                 {
  856.                     curpos = 0;
  857.                 }
  858.             }
  859.             if(inv_ptr >= player->inventorySlotNum)
  860.             {
  861.                 inv_ptr = player->inventorySlotNum-1;
  862.             }
  863.             if(inv_ptr < 0)
  864.             {
  865.                 inv_ptr = 0;
  866.             }
  867.             player->readyArtifact =
  868.                 player->inventory[inv_ptr].type;
  869.         }
  870.     }
  871. }
  872.  
  873. //----------------------------------------------------------------------------
  874. //
  875. // PROC P_PlayerUseArtifact
  876. //
  877. //----------------------------------------------------------------------------
  878.  
  879. void P_PlayerUseArtifact(player_t *player, artitype_t arti)
  880. {
  881.     int i;
  882.  
  883.     for(i = 0; i < player->inventorySlotNum; i++)
  884.     {
  885.         if(player->inventory[i].type == arti)
  886.         { // Found match - try to use
  887.             if(P_UseArtifact(player, arti))
  888.             { // Artifact was used - remove it from inventory
  889.                 P_PlayerRemoveArtifact(player, i);
  890.                 if(player == &players[consoleplayer])
  891.                 {
  892.                     S_StartSound(NULL, sfx_artiuse);
  893.                     ArtifactFlash = 4;
  894.                 }
  895.             }
  896.             else
  897.             { // Unable to use artifact, advance pointer
  898.                 P_PlayerNextArtifact(player);
  899.             }
  900.             break;
  901.         }
  902.     }
  903. }
  904.  
  905. //----------------------------------------------------------------------------
  906. //
  907. // FUNC P_UseArtifact
  908. //
  909. // Returns true if artifact was used.
  910. //
  911. //----------------------------------------------------------------------------
  912.  
  913. boolean P_UseArtifact(player_t *player, artitype_t arti)
  914. {
  915.     mobj_t *mo;
  916.     angle_t angle;
  917.  
  918.     switch(arti)
  919.     {
  920.         case arti_invulnerability:
  921.             if(!P_GivePower(player, pw_invulnerability))
  922.             {
  923.                 return(false);
  924.             }
  925.             break;
  926.         case arti_invisibility:
  927.             if(!P_GivePower(player, pw_invisibility))
  928.             {
  929.                 return(false);
  930.             }
  931.             break;
  932.         case arti_health:
  933.             if(!P_GiveBody(player, 25))
  934.             {
  935.                 return(false);
  936.             }
  937.             break;
  938.         case arti_superhealth:
  939.             if(!P_GiveBody(player, 100))
  940.             {
  941.                 return(false);
  942.             }
  943.             break;
  944.         case arti_tomeofpower:
  945.             if(player->chickenTics)
  946.             { // Attempt to undo chicken
  947.                 if(P_UndoPlayerChicken(player) == false)
  948.                 { // Failed
  949.                     P_DamageMobj(player->mo, NULL, NULL, 10000);
  950.                 }
  951.                 else
  952.                 { // Succeeded
  953.                     player->chickenTics = 0;
  954.                     S_StartSound(player->mo, sfx_wpnup);
  955.                 }
  956.             }
  957.             else
  958.             {
  959.                 if(!P_GivePower(player, pw_weaponlevel2))
  960.                 {
  961.                     return(false);
  962.                 }
  963.                 if(player->readyweapon == wp_staff)
  964.                 {
  965.                     P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1);
  966.                 }
  967.                 else if(player->readyweapon == wp_gauntlets)
  968.                 {
  969.                     P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1);
  970.                 }
  971.             }
  972.             break;
  973.         case arti_torch:
  974.             if(!P_GivePower(player, pw_infrared))
  975.             {
  976.                 return(false);
  977.             }
  978.             break;
  979.         case arti_firebomb:
  980.             angle = player->mo->angle>>ANGLETOFINESHIFT;
  981.             mo = P_SpawnMobj(player->mo->x+24*finecosine[angle],
  982.                 player->mo->y+24*finesine[angle], player->mo->z - 15*FRACUNIT*
  983.                 (player->mo->flags2&MF2_FEETARECLIPPED != 0), MT_FIREBOMB);
  984.             mo->target = player->mo;
  985.             break;
  986.         case arti_egg:
  987.             mo = player->mo;
  988.             P_SpawnPlayerMissile(mo, MT_EGGFX);
  989.             P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
  990.             P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
  991.             P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
  992.             P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
  993.             break;
  994.         case arti_fly:
  995.             if(!P_GivePower(player, pw_flight))
  996.             {
  997.                 return(false);
  998.             }
  999.             break;
  1000.         case arti_teleport:
  1001.             P_ArtiTele(player);
  1002.             break;
  1003.         default:
  1004.             return(false);
  1005.     }
  1006.     return(true);
  1007. }
  1008.